import { updateNodeElement } from "../DOM"
import { createTaskQueue, arrified, createStateNode, getTag, getRoot } from "../Misc"
const taskQueue = createTaskQueue()
let subTask = null
let pendingCommit = null
const commitAllWork = fiber => {
    fiber.effects.forEach(item => {
        if(item.tag === "class_component"){
            item.stateNode.__fiber = item
        }
        if(item.effectTag==="delete"){
          item.parent.stateNode.removeChild(item.stateNode)
        }else  if (item.effectTag === "update") {
            // 更新
            if (item.type === item.alternate.type) {
                // 节点类型相同
                updateNodeElement(item.stateNode, item, item.alternate)
            } else {
                // 节点类型不同 
                item.parent.stateNode.replaceChild(
                    item.stateNode,
                    item.alternate.stateNode
                )
            }
        } else if (item.effectTag === "placement") {
            let fiber = item
            let parentFiber = item.parent
            while (parentFiber.tag === "class_component" || parentFiber.tag === "function_component") {
                parentFiber = parentFiber.parent
            }
            if (fiber.tag === "host_component") {
                parentFiber.stateNode.appendChild(item.stateNode)
            }
        }
    })
    // 备份旧的 fiber 对象
    fiber.stateNode.__rootFiberContainer = fiber
}
const getFirstTask = () => {
    //    从任务队列中获取任务
    const task = taskQueue.pop()
    if(task.from === "class_component"){
        const root = getRoot(task.instance)
        task.instance.__fiber.partialState = task.partialState
        return {
            props: root.props,
            child: null,
            stateNode: root.stateNode,
            tag: "hostRoot",
            effects: [],
            alternate: root
        }
    }
    return {
        props: task.props,
        child: null,
        stateNode: task.dom,
        tag: "hostRoot",
        effects: [],
        alternate: task.dom.__rootFiberContainer
    }
}
const reconcileChildren = (fiber, children) => {
    console.log(children)
    // children可能是对象也可能是数组
    // 讲children转化成数组
    const arrifiedChildren = arrified(children);
    let index = 0
    let numberOfElements = arrifiedChildren.length
    let element = null
    let newFiber = null
    let prevFiber = null
    let alternate = null
    if (fiber.alternate && fiber.alternate.child) {
        alternate = fiber.alternate.child
    }
    while (numberOfElements > index || alternate ) {
        element = arrifiedChildren[index]
        if(!element && alternate){
            // 删除操作
            alternate.effectTag = "delete"
            fiber.effects.push(alternate)
        }
        if (element && alternate) {
            // 更新
            newFiber = {
                type: element.type,
                props: element.props,
                tag: getTag(element),
                effects: [],
                effectTag: "update",
                parent: fiber,
                alternate
            }
            if (element.type === alternate.type) {
                // 类型相同
                newFiber.stateNode = alternate.stateNode
            } else {
                // 类型不同
                newFiber.stateNode = createStateNode(newFiber)
            }
        } else if (element && !alternate) {
            // 初始渲染
            newFiber = {
                type: element.type,
                props: element.props,
                tag: getTag(element),
                effects: [],
                effectTag: "placement",
                parent: fiber
            }
            console.log(newFiber)
            newFiber.stateNode = createStateNode(newFiber)
        }
        // 为父级fiber添加子级 fiber
        if (index === 0) {//第一个子节点
            fiber.child = newFiber
        } else if(element){
            // 第二个子节点设置下一个同级节点
            // 为fiber添加下一个兄弟fiber
            prevFiber.sibling = newFiber
        }
        if (alternate && alternate.sibling) {
            alternate = alternate.sibling
        } else {
            alternate = null
        }
        prevFiber = newFiber
        index++
    }

}
const executeTask = fiber => {
    if (fiber.tag === "class_component") {
        if(fiber.stateNode.__fiber && fiber.stateNode.__fiber.partialState){
            fiber.stateNode.state = {
                ...fiber.stateNode.state,
                ...fiber.stateNode.__fiber.partialState
            }
        }
        reconcileChildren(fiber, fiber.stateNode.render())
    } else if (fiber.tag === "function_component") {
        reconcileChildren(fiber, fiber.stateNode(fiber.props))
    } else {
        reconcileChildren(fiber, fiber.props.children)
    }
    if (fiber.child) {
        return fiber.child
    }
    let currentExecutelyFiber = fiber
    while (currentExecutelyFiber.parent) {
        currentExecutelyFiber.parent.effects = currentExecutelyFiber.parent.effects.concat(currentExecutelyFiber.effects.concat([currentExecutelyFiber]))
        if (currentExecutelyFiber.sibling) {
            return currentExecutelyFiber.sibling
        }
        currentExecutelyFiber = currentExecutelyFiber.parent
    }
    pendingCommit = currentExecutelyFiber
}
const workLook = (deadline) => {
    // 2，判断任务存不存在，调用getFirstTask方法获取任务
    if (!subTask) {
        subTask = getFirstTask()
    }
    // 3,任务存在，并且浏览器有空余时间,调用executeTask方法执行任务
    while (subTask && deadline.timeRemaining() > 1) {
        // executeTask方法只有返回新的任务，while循环才能够继续执行
        subTask = executeTask(subTask)
    }
    if (pendingCommit) {
        commitAllWork(pendingCommit)
    }
}
const perfromtask = deadline => {
    // 1,浏览器有空余时间调用workLook方法
    workLook(deadline)
    // 5,如果subTask有值或者taskQueue还有任务，告诉浏览器空余时间继续执行任务
    // 判断任务是否存在
    // 判断任务队列中是否还有任务没有执行
    // 如果任务没有执行，再次告诉浏览器在空闲的时间执行任务
    if (subTask || !taskQueue.isEmpty()) {
        requestIdleCallback(perfromtask)
    }
}
export const render = (element, dom) => {
    //    1,向任务队列中添加任务
    //    2,指定在浏览器空余时间执行任务
    // 任务就是通过vdom对象构建fiber对象
   
    taskQueue.push({
        dom,
        props: { children: element }
    })
    // 指定在浏览器空闲时间执行任务
    requestIdleCallback(perfromtask)

}

export const scheduleUpdate = (instance,partialState)=>{
    taskQueue.push({
        from:"class_component",
        instance,
        partialState
    })
    requestIdleCallback(perfromtask)
}
